package ace.module.captcha.core.impl.service.impl;

import ace.cmp.converter.api.AceConverter;
import ace.cmp.converter.api.ConverterService;
import ace.module.captcha.api.model.dto.CaptchaImageDto;
import ace.module.captcha.core.impl.controller.graphql.model.dto.CaptchaItemBase64DataImageDto;
import ace.module.captcha.core.impl.converter.CaptchaItemConverter;
import ace.module.captcha.core.impl.dao.entity.CaptchaApplication;
import ace.module.captcha.core.impl.dao.entity.CaptchaComponentConfig;
import ace.module.captcha.core.impl.dao.entity.CaptchaItem;
import ace.module.captcha.core.impl.manager.CaptchaApplicationManager;
import ace.module.captcha.core.impl.manager.CaptchaComponentConfigManager;
import ace.module.captcha.core.impl.manager.CaptchaDataImageManager;
import ace.module.captcha.core.impl.manager.CaptchaItemManager;
import ace.module.captcha.core.impl.manager.handler.CaptchaImageHandlerManager;
import ace.module.captcha.core.impl.manager.handler.model.dto.CaptchaImageStreamResultDto;
import ace.module.captcha.core.impl.service.CaptchaImageService;
import ace.module.captcha.core.impl.service.model.CaptchaImageCreateResultBo;
import java.io.ByteArrayOutputStream;
import lombok.SneakyThrows;
import org.springframework.stereotype.Component;

/**
 * @author Caspar
 * @create 2020/11/5
 */
@Component
public class CaptchaImageServiceImpl implements CaptchaImageService {
  private final CaptchaItemManager captchaItemManager;
  private final CaptchaItemConverter captchaItemConverter;
  private final CaptchaImageHandlerManager captchaImageHandlerManager;
  private final CaptchaApplicationManager captchaApplicationManager;
  private final CaptchaComponentConfigManager captchaComponentConfigManager;
  private final CaptchaDataImageManager captchaDataImageManager;
  private final ConverterService converterService;
  private final AceConverter<CaptchaItem, CaptchaItemBase64DataImageDto>
      captchaItemToCaptchaItemBase64DataImageDtoConverter;

  public CaptchaImageServiceImpl(
      CaptchaItemManager captchaItemManager,
      CaptchaItemConverter captchaItemConverter,
      CaptchaImageHandlerManager captchaImageHandlerManager,
      CaptchaApplicationManager captchaApplicationManager,
      CaptchaComponentConfigManager captchaComponentConfigManager,
      CaptchaDataImageManager captchaDataImageManager,
      ConverterService converterService) {
    this.captchaItemManager = captchaItemManager;
    this.captchaItemConverter = captchaItemConverter;
    this.captchaImageHandlerManager = captchaImageHandlerManager;
    this.captchaApplicationManager = captchaApplicationManager;
    this.captchaComponentConfigManager = captchaComponentConfigManager;
    this.captchaDataImageManager = captchaDataImageManager;
    this.converterService = converterService;
    this.captchaItemToCaptchaItemBase64DataImageDtoConverter =
        this.converterService.getOrCreate(CaptchaItem.class, CaptchaItemBase64DataImageDto.class);
  }

  @Override
  public CaptchaImageCreateResultBo create(Long captchaAppId) {
    CaptchaApplication captchaApplication =
        this.captchaApplicationManager.getByIdAndCheckAll(captchaAppId);

    CaptchaComponentConfig componentConfig =
        this.captchaComponentConfigManager.getById(captchaAppId);

    CaptchaImageStreamResultDto captchaImageResultDTO =
        captchaImageHandlerManager.createImage(componentConfig);

    ByteArrayOutputStream imageOutputStream = captchaImageResultDTO.getImageOutputStream();

    CaptchaItem captchaItem =
        this.captchaItemManager.create(captchaApplication, captchaImageResultDTO.getCode());

    return CaptchaImageCreateResultBo.builder()
        .imageOutputStream(imageOutputStream)
        .captchaItem(captchaItem)
        .build();
  }

  @SneakyThrows
  @Override
  public CaptchaImageDto createBase64(Long captchAppId) {
    CaptchaImageCreateResultBo captchaImageCreateResultBo = this.create(captchAppId);

    String base64Data =
        captchaDataImageManager.toBase64Data(captchaImageCreateResultBo.getImageOutputStream());

    return CaptchaImageDto.builder()
        .captchaItemId(captchaImageCreateResultBo.getCaptchaItem().getId())
        .base64Data(base64Data)
        .build();
  }

  @Override
  public void verify(Long captchaItemId, String code) {
    captchaItemManager.verify(captchaItemId, code);
  }

  @SneakyThrows
  @Override
  public CaptchaItemBase64DataImageDto createBase64WithItem(Long captchaAppId) {
    CaptchaImageCreateResultBo captchaImageCreateResultBo = this.create(captchaAppId);
    String base64Data =
        captchaDataImageManager.toBase64Data(captchaImageCreateResultBo.getImageOutputStream());
    CaptchaItemBase64DataImageDto captchaItemBase64DataImageDto =
        this.captchaItemToCaptchaItemBase64DataImageDtoConverter.convert(
            captchaImageCreateResultBo.getCaptchaItem());
    captchaItemBase64DataImageDto.setBase64Data(base64Data);
    return captchaItemBase64DataImageDto;
  }

  @Override
  public CaptchaImageDto createBase64ByAppKey(String captchAppKey) {
    CaptchaApplication captchaApplication = this.captchaApplicationManager.getByKey(captchAppKey);
    return this.createBase64(captchaApplication.getId());
  }
}
